#pragma once

#include <iostream>
#include <string>
#include <pthread.h>
#include "Socket.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <fstream>
#include <vector>
#include <sstream>
#include <unordered_map>


const std::string wwwroot="./wwwroot";//web根目录
const std::string sep ="\r\n";//反序列化的切割标识符
const std::string homepage ="index.html";//首页

static const int defaultport=8080;

class httpserver;

class ThreadData
{
public:
    ThreadData(int fd,httpserver* s)
        :sockfd(fd)
        ,svr(s)
    {}
public:
    int sockfd;
    httpserver* svr;
};


class HttpRequest
{
public:
    void Deserialize(std::string req)//反序列化
    {
        //字符串切割
        while(true)
        {
            size_t pos=req.find(sep);
            if(pos==std::string::npos) break;//npos是size_t的最大值
            std::string temp=req.substr(0,pos);
            if(temp.empty()) break;  //空串就退出
            req_header.push_back(temp);
            req.erase(0,pos+sep.size());//移除切割的字符串
        }
        text=req;//剩下的部分就是正文

    }
    void Parse()//解析
    {
        std::stringstream ss(req_header[0]);
        ss >> method >> url >> http_version;
        file_path=wwwroot;
        if(url=="/" || url=="/index.html")
        {
            file_path += "/";
            file_path += homepage;
            //     /wwwroot/index.html  就是我的首页
        }
        else
        {
            file_path +=url;
        }
        auto pos =file_path.rfind(".");
        if(pos==std::string::npos) suffix =".html";
        else suffix = file_path.substr(pos);
    }
    void DebugPrint()
    {
        for(auto& line:req_header)
        {
            std::cout << line << "\n\n";
            std::cout << "----------------------------" << std::endl;
        }
        std::cout<<"method: "<<method<<std::endl;
        std::cout<<"url: "<<url<<std::endl;
        std::cout<<"http_version: "<<http_version<<std::endl;
        std::cout<<"file_path: "<<file_path<<std::endl;
        std::cout<<text<<std::endl;
    }
public:
    std::vector<std::string> req_header;//请求报头
    std::string text;//请求正文

    //请求的详细信息
    std::string method;
    std::string url;
    std::string http_version;
    std::string file_path;
    std::string suffix;//文件后缀
};








class httpserver
{
public:
    httpserver(uint16_t port =defaultport)
        :_port(port)
    {
        content_type.insert({".html","text/html"});
        content_type.insert({".png","image/png"});
        content_type.insert({".jpg","image/jpeg"});
    }
    bool start()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        for(;;)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = _listensock.Accept(&clientip,&clientport);
            pthread_t tid;
            ThreadData* td =new ThreadData(sockfd,this);
            pthread_create(&tid,nullptr,ThreadRun,td);
        }
    }

    static std::string ReadHtmlContent(const std::string& htmlpath)
    {
        ////只能读文本
        // std::ifstream in(htmlpath);
        // if(!in.is_open())  return "";

        // std::string content;
        // std::string line;
        // while(std::getline(in,line))
        // {
        //     content +=line;
        // }
        // in.close();
        // return content;
        //可以读取图片----二进制
        std::ifstream in(htmlpath,std::ios::binary);//二进制读取
        if(!in.is_open())  return "";

        in.seekg(0,std::ios_base::end);
        auto len=in.tellg();
        in.seekg(0,std::ios_base::beg);

        std::string content;
        content.resize(len);
        in.read((char*)content.c_str(),content.size());
        in.close();
        return content;
    }


    std::string SuffixToDesc(const std::string &suffix)
    {
        auto iter =content_type.find(suffix);
        if(iter == content_type.end()) return content_type[".html"];
        else return content_type[suffix];
    }
    void HandlerHttp(int sockfd)
    {
        //通过浏览器访问,浏览器发送了一个http请求
        char buffer[1024];
        ssize_t n =recv(sockfd,buffer,sizeof(buffer)-1,0);
        //recv 和 read都可以对TCP套接字进行读取,   recv最后一个参数设置从0就=read
        if(n>0)
        {
            //读取http的请求报文
            buffer[0];
            std::cout<<buffer;
            //假设我们读取到的就是一个完整的,独立的http request

            HttpRequest req;
            req.Deserialize(buffer);//将读取的http request进行反序列化
            req.Parse();
            // req.DebugPrint();




            //返回响应
            std::string text =ReadHtmlContent(req.file_path);//响应正文
            bool ok =true;
            if(text.empty())
            {
                ok =false;
                //如果读取服务器资源失败--不存在
                //text会被返回空串
                //让text变成的404网址err_html
                std::string err_html=wwwroot;
                err_html += "/";
                err_html += "err_html";
                text = ReadHtmlContent(err_html);
            }
            std::string response_line;
            if(ok)
            {
            response_line="HTTP/1.0 200 OK\r\n";//200响应行
            }
            else
            {
            response_line="HTTP/1.0 404 NOT Found\r\n";//404响应行
            }
            // // 302状态码
            // response_line="HTTP/1.0 302 Found\r\n";//302响应行

            //响应报文
            //Content-Length
            std::string response_header="Content-Length: ";
            response_header += std::to_string(text.size());
            response_header +="\r\n";//Content-Length:11 \r\n
            response_header +="Content-Type: ";
            response_header +=SuffixToDesc(req.suffix);
            response_header +="\r\n";
            response_header +="Set-Cookie: name=xy";
            response_header +="\r\n";
            



            //Content-type

            // //测试302---location
            // response_header += "Location:http://www.baidu.com";
            // response_header +="\r\n";

            std::string blank_line ="\r\n";//空行

            std::string response =response_line;
            response +=response_header;
            response +=blank_line;
            response +=text;//组装

            //发送数据  write/send
            ssize_t n = send(sockfd,response.c_str(),response.size(),0);
            //!!!!!!!注意浏览器自动解析response,只会看到text部分
            close(sockfd);
        }
        close(sockfd);
    }
    static void* ThreadRun(void* args)
    {
        ThreadData* td = static_cast<ThreadData*>(args);
        pthread_detach(pthread_self()); //常用的,让线程不用被回收的方法
        td->svr->HandlerHttp(td->sockfd);
        delete td;
        return nullptr;
    }
    ~httpserver()
    {}
private:
    Sock _listensock;
    uint16_t _port;
    std::unordered_map<std::string,std::string> content_type;
    //存储后缀与content-type的对应关系
};